package com.splashcard.engine;

import java.util.HashMap;
import java.util.List;

import com.splashcard.cardsFace.SplashCard;
import com.splashcard.message.GroupExecCallBackMessage;
import com.splashcard.message.ParaMessage;
import com.splashcard.message.SplashCardMessage;
import com.splashcard.tool.util.EngineKernel;
import com.splashcard.tool.util.EngineKernel.KernelFinishCallBack;
/**
 * it is an engine for splashcard running
 * @author helen
 *
 */
public class SplashEngine {
	private static SplashEngine splashEngine = null;

	// the callback interface when card group finish
	public interface OnGroupExecFinish {
		public void OnFinish(GroupExecCallBackMessage result);
	}

	private SplashEngine() {

	}

	//the singleton
	public static SplashEngine getInstance() {
		if (splashEngine == null) {
			splashEngine = new SplashEngine();
		}
		return splashEngine;
	}

	public void exec(final String groupName, List<SplashCard> cards,
			List<ParaMessage> paras, OnGroupExecFinish onGroupExecFinish) {
		//init running flag
		final boolean[] flags = new boolean[cards.size()];
		for (int i = 0; i < flags.length; i++) {
			flags[i] = false;
		}
		//init each card finish callback 
		EnKernelFinishCallBack callBack = new EnKernelFinishCallBack(cards.size(),groupName,
				flags, onGroupExecFinish);
		
		//running each card
		for (int i = 0; i < cards.size(); i++) {
			if (paras == null) {
				//has paras
				EngineKernel.exec(groupName, i, cards.get(i), null, callBack);
			} else {
				//no paras
				ParaMessage para = paras.get(i);
				EngineKernel.exec(groupName, i, cards.get(i), para, callBack);
			}
		}
	}

	// a function rewite for less para
	public void exec(List<SplashCard> cards, List<ParaMessage> paras,
			OnGroupExecFinish onGroupExecFinish) {
		exec("default", cards, paras, onGroupExecFinish);
	}

	// a function rewite for less para 
	public void exec(List<SplashCard> cards, OnGroupExecFinish onGroupExecFinish) {
		exec("default", cards, null, onGroupExecFinish);
	}
	
	//implements the cards exec finish callback
	private class EnKernelFinishCallBack implements KernelFinishCallBack {
		private String groupName;
		private boolean[] flags;
		private OnGroupExecFinish onGroupExecFinish;
		private GroupExecCallBackMessage groupResult;
		private long startTime;
		private int threadNumber = 0;

		public EnKernelFinishCallBack(int threadNumber ,String groupName, boolean[] flags,
				OnGroupExecFinish onGroupExecFinish) {
			super();
			this.groupName = groupName;
			this.flags = flags;
			this.onGroupExecFinish = onGroupExecFinish;
			groupResult = new GroupExecCallBackMessage();
			startTime = System.currentTimeMillis();
			groupResult.put("startTime", startTime);
			this.threadNumber = threadNumber;
		}

		@Override
		public void OnFinish(String groupName, int groupIndex,
				SplashCardMessage result) {
			// TODO Auto-generated method stub
			synchronized (result) {
				//check IF whether group name is the target name
				if (this.groupName.equals(groupName)) {
					//put the card index of group in result set 
					groupResult.put(groupName + "_" + groupIndex, result);
					//reflesh flags
					flags[groupIndex] = true;
					boolean T = true;
					for (int i = 0; i < flags.length; i++) {
						T &= flags[i];
					}
					//check is all is over
					if (T) {
						//put a card set run duration in result set
						long endTime = System.currentTimeMillis();
						groupResult.put("endTime", endTime);
						groupResult.put("usedTime", endTime - startTime);
						groupResult.put("avgUsedTime", (endTime - startTime)/threadNumber);
						groupResult.put("threadNumber", threadNumber);
						if (onGroupExecFinish != null) {
							onGroupExecFinish.OnFinish(groupResult);//all finish 
						}
					}
				}
			}

		}

	}

}
